<?php
/*************
 # 控制器-基类
 # lsj 2009-12-26
************/

if(!defined('APP_HOME')) exit('Access Denied');

class lib_ctrl
{
	protected $view = null;#视图对象
	protected $log = null;#日志对象

	protected static $ctrlName = null;#当前控制器名
	protected static $actionName = null;#当前方法名

	protected static $lastCtrlName = array();#历史跳转控制器名
	protected static $lastActionName = array();#历史跳转方法名

	protected $params = array();#传递给控制器的参数
	public $Cname = '控制器基类';#当前控制器中文含义

	/**
	 * 构造函数
	 * 实例化视图与日志对象
	 */
	public function __construct()
	{
		#强制要求为该控制器一个具体的名称
		if(null === $this->Cname) throw new Exception('Please set Cname.');

		#实例化视图对象
		$this->view = new lib_view($this);
		$this->view->setSuffix('html');
		$this->view->setTemplateRoot(VIEW_ROOT);
		$this->view->setCompiledRoot(VIEWC_ROOT);
		
		#以下是向模板传送的默认数据,很有用的哟!
		$this->view->assign('DOMAIN_ROOT', DOMAIN_ROOT);#站点的根域名
		$this->view->assign('DOMAIN_DOOR', DOMAIN_DOOR);#站点的入口地址
		$this->view->assign('DOMAIN_SRC', DOMAIN_SRC);#资源服务器URL地址

        $this->view->assign('URL_MODE', URL_MODE);#URL地址格式
        $this->view->assign('URL_CTRL_NAME', URL_CTRL_NAME);#URL控制器名
        $this->view->assign('URL_ACT_NAME', URL_ACT_NAME);#URL中动作名
        $this->view->assign('DOMAIN_INDEX', DOMAIN_INDEX);#入口文件名
		
		$this->view->assign('NOW_CTRL', $this->getCtrlName());#当前控制器名
		$this->view->assign('NOW_ACT', $this->getActionName());#当前动作名
		
		$this->view->assign('TITLE', $this->Cname);#当前控制器中文名称	
		
		#初始化，用于子类对构造器的扩展
		$this->_init();
	}

	/**
	 * 实例化时的最后一个工作
	 */
	protected function _init()
	{


	}

    /**
	 * 实例化后的第一个准备工作
	 */
	protected function _first()
	{
        $this->view->assign('THEGLOBALS', $this->getParam('THEGLOBALS'));#公共数组
	}

	/**
	 * 析构函数
	 * 整理并记录日志
	 */
	public function __destruct()
	{
		#自动写日志
		if(1 == IS_LOG && null !== self::$ctrlName){
			//$user = $_COOKIE[COOKIE_USERID];#可将用户ID给写进入
			$this->log = new lib_Log($this);
			$this->log->write($user);
		}

		self::$ctrlName = null;
		self::$actionName = null;
	}

	/**
	 * 为控制器设置参数
	 * 以数组的形式
	 */
	final public function setParam($array = array())
	{
		$array = (array) $array;
		
        	if(isset($array['THEGLOBALS'])){
        		if(!isset($this->params['THEGLOBALS'])) $this->params['THEGLOBALS'] = array();
        		$this->params['THEGLOBALS'] = array_merge($this->params['THEGLOBALS'], $array['THEGLOBALS']);
        		unset($array['THEGLOBALS']);
        	}
        	
        	$this->params = array_merge($this->params, $array);
        	
		return true;
	}

	/**
	 * 获取控制器中传递的参数，与POST GET无关
	 * $name: 参数名[为空时返回所有参数]
	 */
	public function getParam($name = '')
	{
		if($name){
			if(!empty($this->params[$name])) return $this->params[$name];
		}else{
			return $this->params;
		}
		return null;
	}

	/**
	 * 设置当前的控制器名
	 */
	final public function setCtrlName($name)
	{
		if($name != '') self::$ctrlName = $name;
		return $this;
	}

	/**
	 * 设置当前的动作名
	 */
	final public function setActionName($name)
	{
		if($name != '') self::$actionName = $name;
		return $this;
	}
	
	/**
	 * 设置当前的控制器名
	 */
	final public function setLastCtrlName($name)
	{
		if($name != '') self::$lastCtrlName[] = $name;
		return $this;
	}

	/**
	 * 设置当前的动作名
	 */
	final public function setLastActionName($name)
	{
		if($name != '') self::$lastActionName[] = $name;
		return $this;
	}

	/**
	 * 获取当前的控制器名
	 */
	final public function getCtrlName()
	{
		if(self::$ctrlName) return self::$ctrlName;
		return null;
	}

	/**
	 * 获取当前的动作名
	 */
	final public function getActionName()
	{
		if(self::$actionName) return self::$actionName;
		return null;
	}

	/**
	 * 获取走过的控制器名
	 */
	final public function getLastCtrlName()
	{
		return self::$lastCtrlName;
	}

	/**
	 * 获取走过的动作名，与走过的控制器名是对应的
	 */
	final public function getLastActionName()
	{
		return self::$lastActionName;
	}

	/**
	 * 跳转到相应的控制器及对应方法
	 * $act: 对应方法名
	 * $ctrl: 控制器名
	 * $param: 传递的参数
	 */
	final public function forward($ctrl, $act, $param = array())
	{
		if(is_string($param)) $param = parse_str($param);
		$this->setParam($param);
		
		self::setLastCtrlName(self::getCtrlName());
		self::setLastActionName(self::getActionName());

		self::setCtrlName($ctrl);
		self::setActionName($act);

		self::newCtrl($ctrl, $act, $this->getParam());

		return true;
	}

	/**
	 * 页面跳转
	 * $url: 页面的URL地址
	 * $param: 传递的参数
	 */
	final public function redirect($url, $param = array())
	{
		if(headers_sent($file, $line)){
			throw new Exception('Headers already sent in '.$file.' on line '.$line.'.');
		}

		$url = rtrim($url, '?');
		$url = rtrim($url, '&');
		if(!empty($param)) $url .= (false === strpos($url, '?')) ? '?' : '&';

		if(is_array($param)){
			$url .= http_build_query($param);
		}else{
			$url .= $param;
		}

		if(false === strpos($url, 'http://') && false === strpos($url, 'https://')){
			$url = 'http://' . $url;
		}
		header('Location:'.$url);
		exit;
	}

	/**
	 * 加载配置文件
	 */
	final public function loadConfig($filename)
	{
		return loadConfig($filename);
	}

	/**
	 * 加载模型文件
	 */
	final public function loadModel($modname)
	{
		return loadModel($modname);
	}

	/**
	 * 获取控制器的动作所对应的URL
	 */
	final public function getUrl($ctrl='', $act='', $params = array())
	{
		if(!$ctrl) $ctrl = $this->getCtrlName();
        if(!$act) $act = $this->getActionName();
        return getUrl($ctrl, $act, $params);
	}

	/**
	 * 是否为AJAX调用
	 */
	final public function isAjax()
	{
		return isAjax();
	}

	/**
	 * 路由解析
	 */
	private static function route()
	{
		$ctrl = DEFAULT_CTRL;
		$action = DEFAULT_ACTION;

		if(isset($_SERVER['PATH_INFO'])){
			$paths = explode('/', trim($_SERVER['PATH_INFO'], '/'));

			if(isset($paths[0])) $ctrl = array_shift($paths);
			if(isset($paths[0])) $action = array_shift($paths);

			for($i = 0; $i < count($paths); $i = $i + 2){//将参数赋给GET,REQUEST
				if(isset($paths[$i + 1])){
					$_GET[(string)$paths[$i]] = $paths[$i + 1];
					$_REQUEST[(string)$paths[$i]] = $paths[$i + 1];
				}
			}
		}elseif(isset($_SERVER['QUERY_STRING'])){
			parse_str($_SERVER['QUERY_STRING'], $paths);
			if(isset($paths[URL_CTRL_NAME])){
				$ctrl = $paths[URL_CTRL_NAME];
				if(isset($paths[URL_ACT_NAME])){
					$action = $paths[URL_ACT_NAME];
				}
			}else{
				$paths = array_values($paths);
				if(isset($paths[0])){
					$ctrl = array_shift($paths);
				}
				if(isset($paths[0])){
					$action = array_shift($paths);
				}
			}
		}

		self::$ctrlName = $ctrl;
		self::$actionName = $action;
	}

	/**
	 * 调用对应的控制器
	 * 如果$ctrl $act有值，刚会先跳到此控制器
	 */
	public static function GOGOGO($ctrl = '', $act = '', $param = array())
	{
		self::route();
		if($ctrl && $act){
			self::$lastCtrlName[] = self::$ctrlName;
			self::$lastActionName[] = self::$actionName;
			self::$ctrlName = $ctrl;
			self::$actionName = $act;
		}
		self::newCtrl();
	}

	/**
	 * 实例化控制器
	 */
	private static function newCtrl($ctrl = '', $act = '', $param = array())
	{
		if('' !== $ctrl)
			$theCtrl = $ctrl;
		else
			$theCtrl = self::getCtrlName();

		if('' !== $act)
			$theAct = $act;
		else
			$theAct = self::getActionName();

		$theCtrl .= CTRL_SUFFIX;
		$theAct .= ACTION_SUFFIX;

		if(!class_exists($theCtrl)){
			$theCtrl = DEFAULT_CTRL . CTRL_SUFFIX;
			self::setCtrlName(DEFAULT_CTRL);
		} 

		$Controller = new $theCtrl;
		if(!empty($param)) $Controller->setParam($param);
		$Controller->_first();
		$Controller->$theAct();
		unset($Controller);
	}
	
	/**
	 * 向模板引擎中注入变量
	 */
	public function assign($key, $val)
	{
		$this->view->assign($key, $val);
		return $this;
	}
	
	/**
	 * 解析模板文件
	 */
	public function display($ctrl = '', $act = '')
	{
		$this->view->display($ctrl, $act);
		return $this;
	}
	
	/**
	 * 获取模板文件内容
	 */
	public function fetch($ctrl = '', $act = '')
	{
		$this->view->fetch($ctrl, $act);
		return $this;
	}

	/**
	 * 处理不存在的方法
	 */
	public function __call($method, $param)
	{
		if(strpos($method, ACTION_SUFFIX) !== false){
			$method = DEFAULT_ACTION . ACTION_SUFFIX;
			self::setActionName(DEFAULT_ACTION);
			$this->$method();
			return true;
		}
		throw new Exception('The method "'.$method.'" is not exists.');
	}

}

